﻿using System.IO;
// -----------------------------------------------------------------------
// <copyright file="RC2CrytoHelper.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Cryptography_0912089_0912100.CryptoSystem
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Security.Cryptography;
    using System.Windows.Forms;
    using System.IO;
    using Cryptography_0912089_0912100.InputObject;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class RC2CryptoHelper : SymetricCryptoHelper
    {
        public enum Padding { X923, PKSC7, ISO10126 };
        public enum Mode { ECB, CBC, OFB, CFB, CTS };
        public static String PREFIX = ".rc2";

        private Padding _paddingMode = Padding.PKSC7;

        public Padding PaddingMode
        {
            get { return _paddingMode; }
            set { _paddingMode = value; }
        }

        private Mode _operationMode = Mode.CBC;

        public Mode OperationMode
        {
            get { return _operationMode; }
            set { _operationMode = value; }
        }

        private FileStream _fileIn = null;
        private FileStream _fileOut = null;
        private int _maxPerTime = 128;

        public override void Encrypt(object input)
        {
            RC2InputObject inputOBJ = (RC2InputObject)input;
            try
            {
                byte[] key = System.Text.Encoding.UTF8.GetBytes(inputOBJ.Password);
                byte[] IV = System.Text.Encoding.UTF8.GetBytes(inputOBJ.IVString);
                _fileIn = new FileStream(inputOBJ.Input, FileMode.Open, FileAccess.Read);
                _fileOut = new FileStream(inputOBJ.Output + "\\" + Path.GetFileName(inputOBJ.Input) + PREFIX, FileMode.OpenOrCreate, FileAccess.Write);

                byte[] byteIn = new byte[_maxPerTime];
                long readLen = 0;
                long totalLen = _fileIn.Length;
                int lenPerTime = 0;

                RC2 rc2Provider = new RC2CryptoServiceProvider();

                switch (_paddingMode)
                {
                    case Padding.PKSC7:
                        {
                            rc2Provider.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
                            break;
                        }
                    case Padding.X923:
                        {
                            rc2Provider.Padding = System.Security.Cryptography.PaddingMode.ANSIX923;
                            break;
                        }
                    case Padding.ISO10126:
                        {
                            rc2Provider.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
                            break;
                        }
                    default:
                        break;
                }

                switch (_operationMode)
                {
                    case Mode.CBC:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.CBC;
                            break;
                        }
                    case Mode.CFB:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.CFB;
                            break;
                        }
                    case Mode.CTS:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.CTS;
                            break;
                        }
                    case Mode.ECB:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.ECB;
                            break;
                        }
                    case Mode.OFB:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.OFB;
                            break;
                        }
                    default:
                        break;
                }

                CryptoStream encryptStream = new CryptoStream(_fileOut,
                                             rc2Provider.CreateEncryptor(key, IV),
                                             CryptoStreamMode.Write);

                while (readLen < totalLen)
                {
                    lenPerTime = _fileIn.Read(byteIn, 0, _maxPerTime);
                    encryptStream.Write(byteIn, 0, lenPerTime);
                    readLen += lenPerTime;
                }

                encryptStream.Close();
                _fileOut.Close();
                _fileIn.Close();
                MessageBox.Show("Encrypted",
                                    "Infomation",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Information,
                                    MessageBoxDefaultButton.Button1);
            }
            catch (System.Exception ex)
            {
                _fileOut.Close();
                _fileIn.Close();
                MessageBox.Show(ex.Message,
                                    "Error",
                                    MessageBoxButtons.OK,
                                    MessageBoxIcon.Error,
                                    MessageBoxDefaultButton.Button1);
            }
        }

        public override void Decrypt(object input)
        {
            RC2InputObject inputOBJ = (RC2InputObject)input;
            try
            {
                byte[] key = System.Text.Encoding.UTF8.GetBytes(inputOBJ.Password);
                byte[] IV = System.Text.Encoding.UTF8.GetBytes(inputOBJ.IVString);
                _fileIn = new FileStream(inputOBJ.Input, FileMode.Open, FileAccess.Read);
                _fileOut = new FileStream(inputOBJ.Output + "\\" + this.GetDecryptName(inputOBJ.Input, PREFIX), FileMode.OpenOrCreate, FileAccess.Write);

                byte[] byteIn = new byte[_maxPerTime];
                long readLen = 0;
                long totalLen = _fileIn.Length;
                int lenPerTime = 0;

                RC2 rc2Provider = new RC2CryptoServiceProvider();

                switch (_paddingMode)
                {
                    case Padding.PKSC7:
                        {
                            rc2Provider.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
                            break;
                        }
                    case Padding.X923:
                        {
                            rc2Provider.Padding = System.Security.Cryptography.PaddingMode.ANSIX923;
                            break;
                        }
                    case Padding.ISO10126:
                        {
                            rc2Provider.Padding = System.Security.Cryptography.PaddingMode.ISO10126;
                            break;
                        }
                    default:
                        break;
                }

                switch (_operationMode)
                {
                    case Mode.CBC:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.CBC;
                            break;
                        }
                    case Mode.CFB:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.CFB;
                            break;
                        }
                    case Mode.CTS:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.CTS;
                            break;
                        }
                    case Mode.ECB:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.ECB;
                            break;
                        }
                    case Mode.OFB:
                        {
                            rc2Provider.Mode = System.Security.Cryptography.CipherMode.OFB;
                            break;
                        }
                    default:
                        break;
                }

                CryptoStream encryptStream = new CryptoStream(_fileOut,
                                             rc2Provider.CreateDecryptor(key, IV),
                                             CryptoStreamMode.Write);

                while (readLen < totalLen)
                {
                    lenPerTime = _fileIn.Read(byteIn, 0, _maxPerTime);
                    encryptStream.Write(byteIn, 0, lenPerTime);
                    readLen += lenPerTime;
                }

                encryptStream.Close();
                _fileOut.Close();
                _fileIn.Close();
                MessageBox.Show("Decrypted",
                                "Infomation",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Information,
                                MessageBoxDefaultButton.Button1);
            }
            catch (System.Exception ex)
            {
                _fileOut.Close();
                _fileIn.Close();
                MessageBox.Show(ex.Message,
                                "Error",
                                MessageBoxButtons.OK,
                                MessageBoxIcon.Error);

            }
        }
    }
}
